package com.hzw.saas.service.user.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import javax.annotation.Resource;

import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzw.saas.api.product.ILicenseUserService;
import com.hzw.saas.api.product.dto.UserProductInfoDto;
import com.hzw.saas.api.storage.IUserSpaceService;
import com.hzw.saas.api.user.ICustomerLevelService;
import com.hzw.saas.api.user.IUserRightsService;
import com.hzw.saas.api.user.bo.CustomerLevelBO;
import com.hzw.saas.api.user.bo.UserRightsBO;
import com.hzw.saas.api.user.bo.UserStorageRightsBO;
import com.hzw.saas.api.user.bo.ValueCompareBO;
import com.hzw.saas.api.user.constant.UserRightsConsts;
import com.hzw.saas.api.user.query.UserRightsUpdateQuery;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.config.util.MybatisPlusUtil;
import com.hzw.saas.common.util.MapperUtil;
import com.hzw.saas.common.util.SnowFlakeUtil;
import com.hzw.saas.common.util.UnitConvertUtils;
import com.hzw.saas.service.user.mapper.UserRightsMapper;
import com.hzw.saas.service.user.model.UserRights;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 用户权益服务默认实现
 *
 * @author zzl
 * @since 05/11/2021
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class UserRightsServiceImpl extends ServiceImpl<UserRightsMapper, UserRights> implements IUserRightsService, IService<UserRights> {

    @Resource
    private ICustomerLevelService customerLevelService;
    @Resource
    private ILicenseUserService licenseUserService;
    @Resource
    private IUserSpaceService userSpaceService;

    @Override
    public UserRightsBO getUserRightsById(String pid) {
        if (StrUtil.isBlank(pid))
            return null;
        UserRights userRights = super.getById(pid);
        UserRightsBO userRightsBO = MapperUtil.nf().map(userRights, UserRightsBO.class);
        this.defaultValue2GetAndSave(userRightsBO);
        this.setLevelText(userRightsBO);
        return userRightsBO;
    }

    @Override
    public UserRightsBO getUserRightsByUser(String userId) {
        if (StrUtil.isBlank(userId))
            return null;
        List<UserRights> list = this.lambdaQuery().eq(UserRights::getUserId, userId).list();
        if (list.isEmpty())
            return null;
        UserRightsBO userRightsBO = MapperUtil.nf().map(list.get(0), UserRightsBO.class);
        this.defaultValue2GetAndSave(userRightsBO);
        this.setLevelText(userRightsBO);
        List<UserProductInfoDto> userProducts = licenseUserService.listUserProducts(userId);
        userRightsBO.setProducts(userProducts);
        return userRightsBO;
    }

    @Override
    public UserStorageRightsBO getStorageRights(String userId) {
        LambdaQueryChainWrapper<UserRights> query = super.lambdaQuery()
            .select(UserRights::getUserId, UserRights::getCloudStorageSize, UserRights::getCloudStorageExpireTime)
            .eq(UserRights::getUserId, userId);
        MybatisPlusUtil.limitOne(query);
        UserRights userRights = query.one();
        return new UserStorageRightsBO(userRights.getUserId(), userRights.getCloudStorageSize(), userRights.getCloudStorageExpireTime());
    }

    @Override
    public UserRightsBO addUserRights(String userId, String levelId) {
        UserRightsBO userRights = new UserRightsBO();
        userRights.setUserId(userId)
            .setLevelId(levelId);
        return this.addUserRights(userRights);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserRightsBO addUserRights(UserRightsBO rights2Add) {
        AssertUtil.assertThrow("用户ID不可为空", StrUtil.isBlank(rights2Add.getUserId()));
        if (StrUtil.isNotBlank(rights2Add.getLevelId())) {
            CustomerLevelBO levelInfo = customerLevelService.getLevelById(rights2Add.getLevelId());
            AssertUtil.assertThrow("会员级别不存在,levelId: " + rights2Add.getLevelId(), Objects.isNull(levelInfo));
            // 使用levelInfo的属性填充rights2Add中为null的属性
            MapperUtil.nf().map(rights2Add, levelInfo);
            MapperUtil.nf().map(levelInfo, rights2Add);
            Date now = new Date();
            // 设置权益有效期
            if (Objects.isNull(rights2Add.getAwsCoreTimeExpireTime())) {
                rights2Add.setAwsCoreTimeExpireTime(UnitConvertUtils.offsetDatetime(now, levelInfo.getAwsCoreTimeExpire()));
            }
            if (Objects.isNull(rights2Add.getHpcCoreTimeExpireTime())) {
                rights2Add.setHpcCoreTimeExpireTime(UnitConvertUtils.offsetDatetime(now, levelInfo.getHpcCoreTimeExpire()));
            }
            if (Objects.isNull(rights2Add.getCloudStorageExpireTime())) {
                rights2Add.setCloudStorageExpireTime(UnitConvertUtils.offsetDatetime(now, levelInfo.getCloudStorageExpire()));
            }
        }
        rights2Add.setPid(SnowFlakeUtil.nextIdStr());
        this.defaultValue2GetAndSave(rights2Add);
        UserRights entity = MapperUtil.nf().map(rights2Add, UserRights.class);
        // 删除脏数据
        this.deleteUserRights(rights2Add.getUserId());
        this.save(entity);
        // TODO: ZZL@09/30/2021 暂时使用总容量上限，不分解各空间容量上限
        // userSpaceService.batchSave(entity.getUserId(), entity.getCloudStorageSize(), entity.getCloudStorageExpireTime());
        return rights2Add;
    }

    @Override
    public boolean updateUserRights(String userId, String levelId, boolean keepHigherRights) {
        AssertUtil.assertThrow("userId或levelId为空", StrUtil.hasBlank(userId, levelId));
        CustomerLevelBO levelInfo = customerLevelService.getLevelById(levelId);
        AssertUtil.assertThrow("会员级别不存在,levelId: " + levelId, Objects.isNull(levelInfo));
        UserRightsUpdateQuery rights2Update = MapperUtil.nf().map(levelInfo, UserRightsUpdateQuery.class);
        rights2Update.setUserId(userId)
            .setLevelId(levelId);
        return this.updateUserRights(rights2Update, keepHigherRights);
    }

    @Override
    public boolean updateUserRights(UserRightsUpdateQuery rights2Update, boolean keepHigherRights) {
        AssertUtil.assertThrow("用户ID和PID不可同时为空", StrUtil.isAllBlank(rights2Update.getPid(), rights2Update.getUserId()));
        UserRightsBO origin = StrUtil.isBlank(rights2Update.getPid()) ?
            this.getUserRightsByUser(rights2Update.getUserId()) : this.getUserRightsById(rights2Update.getPid());
        AssertUtil.assertThrow("用户权益数据不存在: " + rights2Update.getUserId(), Objects.isNull(origin));
        rights2Update.setPid(origin.getPid());
        UserRightsBO newOne = MapperUtil.nf().map(rights2Update, UserRightsBO.class);
        this.defaultValue2Update(newOne);
        if (keepHigherRights) {
            this.compareUserRights(origin, newOne);
        }
        UserRights entity = MapperUtil.nf().map(newOne, UserRights.class);
        String cloudSize = null;
        if (Objects.nonNull(entity.getCloudStorageSize()) && !Objects.equals(entity.getCloudStorageSize(), origin.getCloudStorageSize()))
            cloudSize = entity.getCloudStorageSize();
        // TODO: ZZL@09/30/2021 暂时使用总容量上限，不分解各空间容量上限
        // if (Objects.isNull(cloudSize)) {
        //     userSpaceService.batchUpdate(entity.getUserId(), null, entity.getCloudStorageExpireTime());
        // } else {
        //     userSpaceService.batchSave(entity.getUserId(), cloudSize, entity.getCloudStorageExpireTime());
        // }
        return this.updateById(entity);
    }

    @Override
    public boolean deleteUserRights(String userId) {
        AssertUtil.assertThrow("用户ID不可为空", StrUtil.isBlank(userId));
        return this.removeById(userId);
    }

    @Override
    public List<ValueCompareBO<?>> compareUserRights(String userId, String newLevelId) {
        UserRightsBO originRights = this.getUserRightsByUser(userId);
        CustomerLevelBO newLevel = customerLevelService.getLevelById(newLevelId);
        if (Objects.isNull(originRights))
            originRights = new UserRightsBO();
        if (Objects.isNull(newLevel))
            newLevel = new CustomerLevelBO();
        List<ValueCompareBO<?>> result = new ArrayList<>();
        // awsCoreTime
        ValueCompareBO<Double> coAwsCoreTime = new ValueCompareBO<>();
        coAwsCoreTime.setProperty("awsCoreTime");
        coAwsCoreTime.setPropertyText("AWS核时总数");
        coAwsCoreTime.setOldValue(originRights.getAwsCoreTime());
        coAwsCoreTime.setNewValue(newLevel.getAwsCoreTime());
        coAwsCoreTime.setHigher(ObjectUtil.compare(coAwsCoreTime.getNewValue(), coAwsCoreTime.getOldValue()) > 0);
        result.add(coAwsCoreTime);
        // awsCoreTimeExpire
        /*ValueCompareBO<Date> coAwsCoreTimeExpire = new ValueCompareBO<>();
        coAwsCoreTimeExpire.setProperty("awsCoreTimeExpire");
        coAwsCoreTimeExpire.setPropertyText("AWS核时有效期");
        coAwsCoreTimeExpire.setOldValue(originRights.getAwsCoreTimeExpireTime());
        coAwsCoreTimeExpire.setNewValue(originRights.getAwsCoreTimeExpireTime());
        coAwsCoreTimeExpire.setHigher(false);
        result.add(coAwsCoreTimeExpire);*/
        // hpcCoreTime
        ValueCompareBO<Double> coHpcCoreTime = new ValueCompareBO<>();
        coHpcCoreTime.setProperty("hpcCoreTime");
        coHpcCoreTime.setPropertyText("HPC核时总数");
        coHpcCoreTime.setOldValue(originRights.getHpcCoreTime());
        coHpcCoreTime.setNewValue(newLevel.getHpcCoreTime());
        coHpcCoreTime.setHigher(ObjectUtil.compare(coHpcCoreTime.getNewValue(), coHpcCoreTime.getOldValue()) > 0);
        result.add(coHpcCoreTime);
        // hpcCoreTimeExpire
        /*ValueCompareBO<Date> coHpcCoreTimeExpire = new ValueCompareBO<>();
        coHpcCoreTimeExpire.setProperty("hpcCoreTimeExpire");
        coHpcCoreTimeExpire.setPropertyText("HPC核时有效期");
        coHpcCoreTimeExpire.setOldValue(originRights.getHpcCoreTimeExpireTime());
        coHpcCoreTimeExpire.setNewValue(originRights.getHpcCoreTimeExpireTime());
        coHpcCoreTimeExpire.setHigher(false);
        result.add(coHpcCoreTimeExpire);*/
        // cloudStorageSize
        ValueCompareBO<String> coCloudStorageSize = new ValueCompareBO<>();
        coCloudStorageSize.setProperty("cloudStorageSize");
        coCloudStorageSize.setPropertyText("云存储空间大小(单位T/G/M)");
        coCloudStorageSize.setOldValue(originRights.getCloudStorageSize());
        coCloudStorageSize.setNewValue(newLevel.getCloudStorageSize());
        coCloudStorageSize.setHigher(UnitConvertUtils.compareStorage(coCloudStorageSize.getNewValue(), coCloudStorageSize.getOldValue()) > 0);
        result.add(coCloudStorageSize);
        // cloudStorageExpire
        /*ValueCompareBO<Date> coCloudStorageExpire = new ValueCompareBO<>();
        coCloudStorageExpire.setProperty("cloudStorageExpire");
        coCloudStorageExpire.setPropertyText("云存储空间有效期");
        coCloudStorageExpire.setOldValue(originRights.getCloudStorageExpireTime());
        coCloudStorageExpire.setNewValue(originRights.getCloudStorageExpireTime());
        coCloudStorageExpire.setHigher(false);
        result.add(coCloudStorageExpire);*/
        // dockerNumber
        ValueCompareBO<Integer> coDockerNumber = new ValueCompareBO<>();
        coDockerNumber.setProperty("dockerNumber");
        coDockerNumber.setPropertyText("可用docker数");
        coDockerNumber.setOldValue(originRights.getDockerNumber());
        coDockerNumber.setNewValue(newLevel.getDockerNumber());
        coDockerNumber.setHigher(ObjectUtil.compare(coDockerNumber.getNewValue(), coDockerNumber.getOldValue()) > 0);
        result.add(coDockerNumber);
        // dockerRecycleDuration
        ValueCompareBO<String> coDockerRecycleDuration = new ValueCompareBO<>();
        coDockerRecycleDuration.setProperty("dockerRecycleDuration");
        coDockerRecycleDuration.setPropertyText("docker自动回收时长(单位H/m)");
        coDockerRecycleDuration.setOldValue(originRights.getDockerRecycleDuration());
        coDockerRecycleDuration.setNewValue(newLevel.getDockerRecycleDuration());
        coDockerRecycleDuration.setHigher(UnitConvertUtils.compareDatetime(coDockerRecycleDuration.getNewValue(), coDockerRecycleDuration.getOldValue()) > 0);
        result.add(coDockerRecycleDuration);
        return result;
    }

    /**
     * 使用原权益中较高的值替换新权益中较低的值
     *
     * @param origin
     * @param newOne
     */
    private void compareUserRights(UserRightsBO origin, UserRightsBO newOne) {
        if (Objects.isNull(origin))
            return;
        if (Objects.isNull(newOne)) {
            return;
        }
        // awsCoreTime
        if (ObjectUtil.compare(origin.getAwsCoreTime(), newOne.getAwsCoreTime()) > 0)
            newOne.setAwsCoreTime(origin.getAwsCoreTime());
        // awsCoreTimeExpire
        if (ObjectUtil.compare(origin.getAwsCoreTimeExpireTime(), newOne.getAwsCoreTimeExpireTime()) > 0)
            newOne.setAwsCoreTimeExpireTime(origin.getAwsCoreTimeExpireTime());
        // hpcCoreTime
        if (ObjectUtil.compare(origin.getHpcCoreTime(), newOne.getHpcCoreTime()) > 0)
            newOne.setHpcCoreTime(origin.getHpcCoreTime());
        // hpcCoreTimeExpire
        if (ObjectUtil.compare(origin.getHpcCoreTimeExpireTime(), newOne.getHpcCoreTimeExpireTime()) > 0)
            newOne.setHpcCoreTimeExpireTime(origin.getHpcCoreTimeExpireTime());
        // cloudStorageSize
        if (UnitConvertUtils.compareStorage(origin.getCloudStorageSize(), newOne.getCloudStorageSize()) > 0)
            newOne.setCloudStorageSize(origin.getCloudStorageSize());
        // cloudStorageExpire
        if (ObjectUtil.compare(origin.getCloudStorageExpireTime(), newOne.getCloudStorageExpireTime()) > 0)
            newOne.setCloudStorageExpireTime(origin.getCloudStorageExpireTime());
        // dockerNumber
        if (ObjectUtil.compare(origin.getDockerNumber(), newOne.getDockerNumber()) > 0)
            newOne.setDockerNumber(origin.getDockerNumber());
        // dockerRecycleDuration
        if (UnitConvertUtils.compareDatetime(origin.getDockerRecycleDuration(), newOne.getDockerRecycleDuration()) > 0)
            newOne.setDockerRecycleDuration(origin.getDockerRecycleDuration());
    }

    private void setLevelText(UserRightsBO userRightsBO) {
        CustomerLevelBO levelInfo = customerLevelService.getLevelById(userRightsBO.getLevelId());
        if (Objects.isNull(levelInfo))
            return;
        userRightsBO.setLevelText(levelInfo.getLevelText())
            .setLevelDisplayText(levelInfo.getLevelDisplayText());
    }

    private void defaultValue2GetAndSave(UserRightsBO rights) {
        if (Objects.isNull(rights.getAwsCoreTime()))
            rights.setAwsCoreTime(UserRightsConsts.DEFAULT_CORE_TIME);
        if (Objects.isNull(rights.getHpcCoreTime()))
            rights.setHpcCoreTime(UserRightsConsts.DEFAULT_CORE_TIME);
        if (Objects.isNull(rights.getHpcCoreTime()))
            rights.setHpcCoreTime(UserRightsConsts.DEFAULT_CORE_TIME);
        if (Objects.isNull(rights.getDockerNumber()))
            rights.setDockerNumber(UserRightsConsts.DEFAULT_DOCKER_NUM);
        if (StrUtil.isBlank(rights.getCloudStorageSize()))
            rights.setCloudStorageSize(UserRightsConsts.DEFAULT_CLOUD_STORAGE_SIZE);
        if (StrUtil.isBlank(rights.getDockerRecycleDuration()))
            rights.setDockerRecycleDuration(UserRightsConsts.DEFAULT_DOCKER_RECYCLE_DURATION);
    }

    private void defaultValue2Update(UserRightsBO rights) {
        if (Objects.nonNull(rights.getCloudStorageSize()) && StrUtil.isBlank(rights.getCloudStorageSize()))
            rights.setCloudStorageSize(UserRightsConsts.DEFAULT_CLOUD_STORAGE_SIZE);
        if (Objects.nonNull(rights.getDockerRecycleDuration()) && StrUtil.isBlank(rights.getDockerRecycleDuration()))
            rights.setDockerRecycleDuration(UserRightsConsts.DEFAULT_DOCKER_RECYCLE_DURATION);
    }

}
